<template>
	<transition name="viewer-fade">
		<div tabindex="-1" ref="el-image-viewer__wrapper" class="el-image-viewer__wrapper" :style="{ 'z-index': zIndex }">
			<div class="el-image-viewer__mask"></div>
			<!-- CLOSE -->
			<span class="el-image-viewer__btn el-image-viewer__close" @click="hide">
				<i class="el-icon-circle-close"></i>
			  </span>
			<!-- ARROW -->
			<template v-if="!isSingle">
				<span
						class="el-image-viewer__btn el-image-viewer__prev"
						:class="{ 'is-disabled': !infinite && isFirst }"
						@click="prev">
				  <i class="el-icon-arrow-left"/>
				</span>
						<span
								class="el-image-viewer__btn el-image-viewer__next"
								:class="{ 'is-disabled': !infinite && isLast }"
								@click="next">
				  <i class="el-icon-arrow-right"/>
				</span>
			</template>
			<!-- CANVAS -->
			<div class="el-image-viewer__canvas">
				<video v-for="(url, i) in urlList"
					   v-if="i === index"
					   ref="img"
					   class="el-image-viewer__img"
					   :key="url"
					   :src="currentVideo"
					   :style="videoStyle"
					   controls
				/>
			</div>
		</div>
	</transition>
</template>

<script>
    import { on, off } from 'element-ui/src/utils/dom';
    import { rafThrottle, isFirefox } from 'element-ui/src/utils/util';

    const Mode = {
        CONTAIN: {
            name: 'contain',
            icon: 'el-icon-full-screen'
        },
        ORIGINAL: {
            name: 'original',
            icon: 'el-icon-c-scale-to-original'
        }
    };

    const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel';

    export default {
        name: 'elImageViewer',

        props: {
            urlList: {
                type: Array,
                default: () => []
            },
            zIndex: {
                type: Number,
                default: 2000
            },
            onSwitch: {
                type: Function,
                default: () => {}
            },
            onClose: {
                type: Function,
                default: () => {}
            },
            initialIndex: {
                type: Number,
                default: 0
            }
        },

        data() {
            return {
                index: this.initialIndex,
                isShow: false,
                infinite: true,
                loading: false,
                mode: Mode.CONTAIN,
                transform: {
                    scale: 1,
                    deg: 0,
                    offsetX: 0,
                    offsetY: 0,
                    enableTransition: false
                }
            };
        },
        computed: {
            isSingle() {
                return this.urlList.length <= 1;
            },
            isFirst() {
                return this.index === 0;
            },
            isLast() {
                return this.index === this.urlList.length - 1;
            },
            currentVideo() {
                return this.urlList[this.index];
            },
            videoStyle() {
                const { scale, deg, offsetX, offsetY, enableTransition } = this.transform;
                const style = {
                    transform: `scale(${scale}) rotate(${deg}deg)`,
                    transition: enableTransition ? 'transform .3s' : '',
                    'margin-left': `${offsetX}px`,
                    'margin-top': `${offsetY}px`
                };
                if (this.mode === Mode.CONTAIN) {
                    style.maxWidth = style.maxHeight = '100%';
                }
                return style;
            }
        },
        watch: {
            index: {
                handler: function(val) {
                    this.reset();
                    this.onSwitch(val);
                }
            },
            currentImg(val) {
                this.$nextTick(_ => {
                    const $img = this.$refs.img[0];
                    if (!$img.complete) {
                        this.loading = true;
                    }
                });
            }
        },
        methods: {
            hide() {
                this.deviceSupportUninstall();
                this.onClose();
            },
            deviceSupportInstall() {
                this._keyDownHandler = rafThrottle(e => {
                    const keyCode = e.keyCode;
                    switch (keyCode) {
                        // ESC
                        case 27:
                            this.hide();
                            break;
                        // SPACE
                        case 32:
                            this.toggleMode();
                            break;
                        // LEFT_ARROW
                        case 37:
                            this.prev();
                            break;
                        // UP_ARROW
                        case 38:
                            this.handleActions('zoomIn');
                            break;
                        // RIGHT_ARROW
                        case 39:
                            this.next();
                            break;
                        // DOWN_ARROW
                        case 40:
                            this.handleActions('zoomOut');
                            break;
                    }
                });
                this._mouseWheelHandler = rafThrottle(e => {
                    const delta = e.wheelDelta ? e.wheelDelta : -e.detail;
                    if (delta > 0) {
                        this.handleActions('zoomIn', {
                            zoomRate: 0.015,
                            enableTransition: false
                        });
                    } else {
                        this.handleActions('zoomOut', {
                            zoomRate: 0.015,
                            enableTransition: false
                        });
                    }
                });
                on(document, 'keydown', this._keyDownHandler);
                on(document, mousewheelEventName, this._mouseWheelHandler);
            },
            deviceSupportUninstall() {
                off(document, 'keydown', this._keyDownHandler);
                off(document, mousewheelEventName, this._mouseWheelHandler);
                this._keyDownHandler = null;
                this._mouseWheelHandler = null;
            },
            reset() {
                this.transform = {
                    scale: 1,
                    deg: 0,
                    offsetX: 0,
                    offsetY: 0,
                    enableTransition: false
                };
            },
            toggleMode() {
                if (this.loading) return;

                const modeNames = Object.keys(Mode);
                const modeValues = Object.values(Mode);
                const index = modeValues.indexOf(this.mode);
                const nextIndex = (index + 1) % modeNames.length;
                this.mode = Mode[modeNames[nextIndex]];
                this.reset();
            },
            prev() {
                if (this.isFirst && !this.infinite) return;
                const len = this.urlList.length;
                this.index = (this.index - 1 + len) % len;
            },
            next() {
                if (this.isLast && !this.infinite) return;
                const len = this.urlList.length;
                this.index = (this.index + 1) % len;
            },
            handleActions(action, options = {}) {
                if (this.loading) return;
                const { zoomRate, rotateDeg, enableTransition } = {
                    zoomRate: 0.2,
                    rotateDeg: 90,
                    enableTransition: true,
                    ...options
                };
                const { transform } = this;
                switch (action) {
                    case 'zoomOut':
                        if (transform.scale > 0.2) {
                            transform.scale = parseFloat((transform.scale - zoomRate).toFixed(3));
                        }
                        break;
                    case 'zoomIn':
                        transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3));
                        break;
                    case 'clocelise':
                        transform.deg += rotateDeg;
                        break;
                    case 'anticlocelise':
                        transform.deg -= rotateDeg;
                        break;
                }
                transform.enableTransition = enableTransition;
            }
        },
        mounted() {
            this.deviceSupportInstall();
            // add tabindex then wrapper can be focusable via Javascript
            // focus wrapper so arrow key can't cause inner scroll behavior underneath
            this.$refs['el-image-viewer__wrapper'].focus();
        }
    };
</script>
<style>
	.el-icon-circle-close {
		color: #fff;
	}
</style>
